/**
 * @brief local control unit
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <netdb.h>                  //gethostbyname
#include <netinet/in.h>             //inet sockets
#include <arpa/inet.h>              //inet_ntoa

#include <myTCP.h>

int verbose;
const char * program_name;

/** Description of long options for getopt_long.  */
static const struct option long_options[] =
{
    { "address",          1, NULL, 'a' },
    { "help",             0, NULL, 'h' },
    { "dirmod",           1, NULL, 'd' },
    { "module",           1, NULL, 'm' },
    { "port",             1, NULL, 'p' },
    { "verbose",          0, NULL, 'v' },
};

/** Description of short options for getopt_long.  */
static const char* const short_options = "a:hd:m:p:v";

/** Usage summary text.  */
static const char* const usage_template =
        "Usage: %s [ options ]\n"
        "  -a, --address ADDR        Bind to local address (by default, bind\n"
        "                              to all local addresses).\n"
        "  -h, --help                Print this information.\n"
        "  -m, --module MODULE       Module to load and execute.\n"
        "  -d, --dirmod DIR          Load modules from specified directory\n"
        "                              (by default, use executable directory).\n"
        "  -p, --port PORT           Bind to specified port.\n"
        "  -v, --verbose             Print verbose messages.\n";

/** Print usage information and exit.  If IS_ERROR is nonzero, write to
    stderr and use an error exit code.  Otherwise, write to stdout and
    use a non-error termination code.  Does not return.  */
static void print_usage (int is_error)
{
    fprintf( is_error ? stderr : stdout, usage_template, program_name );
    exit( is_error ? 1 : 0 );
}

int main( int argc, char * argv[] )
{
    struct in_addr local_address;
    int next_option;
    uint16_t port;
    int retval;
    //char line[32];

    /** Dont print verbose messages.  */
    verbose = 0;
    /** Set defaults for options.  Bind the server to all local addresses,
    and assign an unused port automatically.  */
    local_address.s_addr = INADDR_ANY;
    port = (uint16_t) htons( 4000 );
    /** Store the program name, which well use in error messages.  */
    program_name = argv[0];
    /** Parse options.  */
    do {
        next_option =
                getopt_long (argc, argv, short_options, long_options, NULL);
        switch (next_option) {
            case 'a':
                /** User specified -a or --address.  */
            {
                struct hostent * local_host_name;
                /** Look up the hostname the user specified.  */
                local_host_name = gethostbyname( optarg );
                if( local_host_name == NULL || local_host_name->h_length == 0 ) {
                    /** Could not resolve the name.  */
                    perror( "[Main] gethostbyname" );
                } else {
                    /** Hostname is OK, so use it.  */
                    local_address.s_addr =  * ( (int *) (local_host_name->h_addr_list[0]) );
                    //printf ("ip %s\n", inet_ntoa( local_address ) );
                }
            }
            break;
            case 'h':
                /** User specified -h or --help.  */
                print_usage( 0 );
            case 'd':
                /** User specified -d or --dirmod.  */
            {
                //struct stat dir_info;
                /** Check that it exists.  */
                //if (access (optarg, F_OK) != 0)
                //    error (optarg, "module directory does not exist");
                /** Check that it is accessible.  */
                //if (access (optarg, R_OK |X_OK) != 0)
                //    error (optarg, "module directory is not accessible");
                /** Make sure that it is a directory.  */
                //if (stat (optarg, &dir_info) != 0 ||!S_ISDIR (dir_info.st_mode))
                //    error (optarg, "not a directory");
                /** It looks OK, so use it.  */
                //module_dir = strdup( optarg );
            }
            break;
            case 'm':
                /** User specified -m or --module.  */
            {
                //struct stat dir_info;
                /** Check that it exists.  */
                //if (access (optarg, F_OK) != 0)
                //    error (optarg, "module directory does not exist");
                /** Check that it is accessible.  */
                //if (access (optarg, R_OK |X_OK) != 0)
                //    error (optarg, "module directory is not accessible");
                /** Make sure that it is a directory.  */
                //if (stat (optarg, &dir_info) != 0 ||!S_ISDIR (dir_info.st_mode))
                //    error (optarg, "not a directory");
                /** It looks OK, so use it.  */
                //module_dir = strdup( optarg );
            }
            break;
            case 'p':
                /** User specified -p or --port.  */
            {
                long value;
                char* end;
                value = strtol( optarg, &end, 10 );
                if (*end != '\0')
                    /** The user specified nondigits in the port number.  */
                    print_usage (1);
                    /** The port number needs to be converted to network (big endian) 
                byte order.  */
                port = (uint16_t) htons (value);
            }
            break;
            case 'v':
                /** User specified -v or --verbose.  */
                verbose = 1;
                break;
            case '?':
                /** User specified an unrecognized option.  */
                print_usage( 1 );
            case -1:
                /** Done with options.  */
                break;
            default:
                abort();
        }
    } while( next_option != -1 );
    /** This program takes no additional arguments.  Issue an error if the 
    user specified any.  */
    if( optind != argc ) {
        print_usage( 1 );
    }

    if( verbose ) printf( "[Main] Hello world\n" );
    if( verbose ) printf( "[Main] My IP  : %s\n", inet_ntoa( local_address ) );
    if( verbose ) printf( "[Main] My port: %d\n", (int) ntohs( port ) );
    myTCP * tcp;
    tcp = new myTCP( local_address, port );
    retval = tcp->server_run();
    if( verbose ) printf( "[Main] tcp->server_run() returned with %d\n", retval );
    //lcu->createTelescope();
    //lcu->waitSemaphore();
    //lcu->configureTelescope();
    //if( verbose) printf( "[Main]  Lat %+10.6lf Telescope Latitude\n", lcu->telescope->getLatitude() );
    //if( verbose) printf( "[Main]  Lng %+10.6lf Telescope Longitude\n", lcu->telescope->getLongitude() );
    //if( verbose) printf( "[Main]  Alt %+10.6lf Telescope Altitude\n", lcu->telescope->getAltitude() );
    //lcu->postSemaphore();
    if( retval == 1 ) {
        if( verbose ) printf( "[Main] The server is down!\n" );
        sleep(1);
        //exit( 0 );
    } else {
        if( verbose ) printf( "[Main] The client is done!\n" );
        //exit( 1 );
    }
    delete tcp;
    if( verbose ) printf( "[Main] Good bye!\n" );
    return 0;
}


